Ctrl-C 做什么
- 用户输入 Ctrl-C
- 驱动程序收到字符
- 匹配 VINTR 和 ISIG 的字符被开启
- 驱动程序调用信号系统
- 信号系统发送 SIGINT 到进程
- 进程收到 SIGINT
- 进程消亡
信号是什么
每个信号都有一个数字编码, 终端信号通常是编码2
- 用户 用户能够通过输入 Ctrl-C 等请求内核产生信号
- 内核 当程序执行出错时, 内核给进程发送一个信号
- 进程 一个进程可以通过心痛调用 kill 给另一个进程发送信号
进程该如何处理信号
- 接受默认处理 signal(SIGINT, SIG_DEL);
- 忽略信号 signal(SIGINT, SIG_IGN);
- 调用一个函数 signal(signum, functionname);
signal | |
---|---|
目标 | 简单的信号处理 |
头文件 | #include <signal.h> |
函数原型 | result = signal(int signum, void (*action)(int)); |
参数 | signum 信号 /action 处理函数 |
返回值 | -1 遇到错误, prevaction 成功 |
action 可以是函数名或一下两个特殊值之一:
- SIG_IGN,忽略信号
- SIG_DFL, 将信号恢复为默认处理
signal 返回前一个处理函数. 值是指向函数的指针.
例子
1. 捕捉信号
sigdemo1.c
#include <stdio.h> #include <signal.h> void f(int); int main() { int i; signal(SIGINT, f); for (i = 0; i < 5; i++){ printf("hello\n"); sleep(1); } return 0; } void f(int signum) { printf("OUCH!\n"); }
主函数由两个部分组成, 调用 signal 后进入一个循环. sigdemo1.c 调 用 signal 来设置 SIGINT 的处理函数f. 如果进程收到 SIGINT 信号, 内核会调用函数 f 来处理这个信号. 程序跳转到那个函数, 执行它的 代码, 然后返回跳转前的位置, 就像子过程调用一样.
2. 忽略信号
sigdemo2.c
#include <stdio.h> #include <signal.h> int main() { signal(SIGINT, SIG_IGN); printf("you can't stop me!\n"); while (1) { sleep(1); printf("haha\n"); } }
为处理信号做准备: paly_again4.c
#include <stdio.h> #include <termios.h> #include <fcntl.h> #include <string.h> #include <signal.h> #define ASK "Do you want another transaction" #define TRIES 3 #define SLEEPTIME 2 #define BEEP putchar('\a') int get_response(char *, int); void tty_mode(int); void set_crmode(); void set_cr_noecho_mode(); void set_nodelay_mode(); char get_ok_char(); void ctrl_c_handler(int); int main() { int response; tty_mode(0); /* save tty mode */ set_cr_noecho_mode(); /* set -icanon, -echo */ set_nodelay_mode(); signal(SIGINT, ctrl_c_handler); signal(SIGQUIT, SIG_IGN); response = get_response(ASK, TRIES); tty_mode(1); /* restore tty mode */ return response; } int get_response(char *question, int maxtries) { int input; printf("%s (y/n)?", question); while(1){ sleep(SLEEPTIME); input = tolower(get_ok_char()); if (input == 'y') return 0; if (input == 'n') return 1; if (maxtries-- == 0) return 2; BEEP; } } char get_ok_char() { int c; while ((c = getchar()) != EOF && strchr("yYnN", c) == NULL) ; return c; } void set_cr_noecho_mode() { struct termios ttystate; tcgetattr(0, &ttystate); ttystate.c_lflag &= ~ICANON; /* no buffering */ ttystate.c_lflag &= ~ECHO; /* no echo either */ ttystate.c_cc[VMIN] = 1; /* get 1 char at a time */ tcsetattr(0, TCSANOW, &ttystate); } void set_nodelay_mode() { int termflags; termflags = fcntl(0, F_GETFL); termflags |= O_NDELAY; fcntl(0, F_SETFL, termflags); } void tty_mode(int how) { static struct termios original_mode; static int original_flags; if (how == 0){ tcgetattr(0, &original_mode); original_flags = fcntl(0, F_GETFL); } else{ tcsetattr(0, TCSANOW, &original_mode); fcntl(0, F_SETFL, original_flags); } } void ctrl_c_handler(int signum) { tty_mode(1); exit(1); }